package com.example.filesystem.interceptor;

import com.example.filesystem.entity.Result;
import com.example.filesystem.service.ILogService;
import com.example.filesystem.util.IpUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

import static com.example.filesystem.config.WebConfig.OPTIONS;

/**
 * @author bbyh
 * @description 流量限流拦截器
 * @since 2025-04-29
 */
@Component
@Slf4j
public class LimitFlowInterceptor implements HandlerInterceptor {
    private static final Integer MB = 1024 * 1024;
    public static String flowInterUuidPrefix;
    private static String flowInterLimitIpPrefix;
    private static String flowInterLimitUserPrefix;
    @Value("${flow.inter.limit.ip.count}")
    private Long flowInterLimitIpCount;
    @Value("${flow.inter.limit.user.count}")
    private Long flowInterLimitUserCount;
    @Value("${ip.inter.limit.set}")
    private String ipInterLimitSet;
    @Value("${user.inter.limit.set}")
    private String userInterLimitSet;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ILogService logService;

    public static void updateFlow(StringRedisTemplate stringRedisTemplate, HttpServletRequest request, String uuid, int size) {
        String ip = IpUtil.getIp(request);
        if (uuid == null) {
            throw new RuntimeException("缺少uuid");
        }
        String username = stringRedisTemplate.opsForValue().get(flowInterUuidPrefix + uuid);
        if (username == null) {
            throw new RuntimeException("无效的uuid：" + uuid);
        }
        updateFlow(stringRedisTemplate, size, flowInterLimitIpPrefix + ip);
        updateFlow(stringRedisTemplate, size, flowInterLimitUserPrefix + username);
    }

    private static void updateFlow(StringRedisTemplate stringRedisTemplate, int size, String key) {
        String count = stringRedisTemplate.opsForValue().get(key);
        if (count == null) {
            stringRedisTemplate.opsForValue().set(key, String.valueOf(size), 3600, TimeUnit.SECONDS);
        } else {
            stringRedisTemplate.opsForValue().set(key, String.valueOf(Long.parseLong(count.trim()) + size), 0);
        }
    }

    @Value("${flow.inter.limit.ip.prefix}")
    public void setFlowInterLimitIpPrefix(String flowInterLimitIpPrefix) {
        LimitFlowInterceptor.flowInterLimitIpPrefix = flowInterLimitIpPrefix;
    }

    @Value("${flow.inter.limit.user.prefix}")
    public void setFlowInterLimitUserPrefix(String flowInterLimitUserPrefix) {
        LimitFlowInterceptor.flowInterLimitUserPrefix = flowInterLimitUserPrefix;
    }

    @Value("${flow.inter.uuid.prefix}")
    public void setFlowInterUuidPrefix(String flowInterUuidPrefix) {
        LimitFlowInterceptor.flowInterUuidPrefix = flowInterUuidPrefix;
    }

    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
        try {
            if (OPTIONS.equals(request.getMethod())) {
                return true;
            }

            String ip = IpUtil.getIp(request);
            String uuid = request.getParameter("uuid");
            String uri = request.getRequestURI();

            if (uuid == null) {
                Result.writeResult(response, "缺少uuid");
                return false;
            }
            String username = stringRedisTemplate.opsForValue().get(flowInterUuidPrefix + uuid);
            if (username == null) {
                Result.writeResult(response, "无效的uuid：" + uuid);
                return false;
            }

            String ipFlowCount = stringRedisTemplate.opsForValue().get(flowInterLimitIpPrefix + ip);
            if (ipFlowCount == null) {
                return true;
            }
            if (Long.parseLong(ipFlowCount.trim()) >= (flowInterLimitIpCount * MB)) {
                stringRedisTemplate.opsForSet().add(ipInterLimitSet, ip);
                logService.saveInterLog(ip, username, uri);
                Result.writeResult(response, "ip：" + ip + "已流量已达到阈值，被加入黑名单");
                return false;
            }

            String userFlowCount = stringRedisTemplate.opsForValue().get(flowInterLimitUserPrefix + username);
            if (userFlowCount == null) {
                return true;
            }
            if (Long.parseLong(userFlowCount.trim()) >= (flowInterLimitUserCount * MB)) {
                stringRedisTemplate.opsForSet().add(userInterLimitSet, ip);
                logService.saveInterLog(ip, username, uri);
                Result.writeResult(response, "用户名：" + username + "已流量已达到阈值，被加入黑名单");
                return false;
            }

            return true;
        } catch (NumberFormatException e) {
            log.error(e.getMessage(), e);
            Result.writeResult(response, "流量限流器服务出错");
            return false;
        }
    }
}
